//DC Manager 
//Reversed by West-Li
//v3

#include <pspkernel.h>
#include <pspnand_driver.h>
#include <string.h>
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>

#include <systemctrl.h>

PSP_MODULE_INFO("DesCemManager", 0x1006, 1, 0);
PSP_MAIN_THREAD_ATTR(0);

//DcManager_A22190CE
//* This function detect hardware info of your PSP *
//NOTE: for this function: i was soo lazy to reversering it :P.. so i use srcs from my kuman.prx = this code is not like dcGetHardwareInfo but it works :)
void dcGetHardwareInfo(int *baryon, int *pommel, int *tachyon, int *mb, int *fuseid, int *fusecfg, int *nandsize)
{
	int pagesize, ppb, totalblocks;
	u32 verb, verp, vert, mbp, cfg, nand;
	u64 id;

	int k1 = pspSdkSetK1(0);
	sceSyscon_driver_7EC5A957(&verb);
	sceSyscon_driver_E7E87741(&verp);
    vert = sceSysreg_driver_E2A5D1EE();
	
	if (vert == 0x00140000) mbp = 0;
	else if (vert == 0x00200000 && verb == 0x00030600) mbp = 1;
	else if (vert == 0x00200000 && verb == 0x00040600) mbp = 2;
	else if (vert == 0x00300000 && verb == 0x00040600 && verp == 0x00000103) mbp = 3;
	else if (vert == 0x00300000 && verb == 0x00040600 && verp == 0x00000104) mbp = 4;
	else if (vert == 0x00400000 && verb == 0x00114000) mbp = 5;
	else if (vert == 0x00400000 && verb == 0x00121000) mbp = 6;
	else if (vert == 0x00500000 && verb == 0x0022B200) mbp = 7;
	else if (vert == 0x00500000 && verb == 0x00234000) mbp = 8;
	else if (vert == 0x00500000 && verb == 0x00243000) mbp = 9;
	else mbp = 10; //Sets MB to "O__O" or "Unknown" if cant detect
	
	id = sceSysreg_driver_4F46EEDE();
	cfg = sceSysreg_driver_8F4F4E96(); 
	nand = dcGetNandInfo(&pagesize, &ppb, &totalblocks) /1024 /1024;
	pspSdkSetK1(k1);
	
	(*baryon) = verb;
	(*pommel) = verp;
    (*tachyon) = vert;
	(*mb) = mbp;
	(*fuseid) = id;
	(*fusecfg) = cfg;
	(*nandsize) = nand;
}

//DcManager_3A3EA355
//* This function will patch some module *
//NOTE: code is unknown (for now)
int dcPatchModule(char *modname, int type, u32 addr, u32 word)
{
	return 0;
}

//DcManager_D298BA53
//* This function will patch some module with string *
//NOTE: code is unknown (for now)
int dcPatchModuleString(char *modname, char *string, char *replace)
{
	return 0;
}

//DcManager_9C87A1C7
//* This will get cancel mode *
//NOTE: code is unknown (for now)
int dcGetCancelMode()
{
	return 0;
}

//DcManager_F5161120
//* This will set cancel mode *
//NOTE: code is unknown (for now)
int dcSetCancelMode(int mode)
{
	return 0;
}

//DcManager_39D91E83
//* This will format selected flash *
//NOTE: thanks neur0n for this code :)
int dcLflashStartFatfmt(int argc, char *argv[])
{
	int k1 = pspSdkSetK1(0); 
	int a0 = sctrlKernelSetUserLevel(4);
	int ret = sceLflashFatfmtStartFatfmt(argc, argv); 
	sctrlKernelSetUserLevel(a0); 
	pspSdkSetK1(k1); 
	return ret; //In asm is return 0;, but if we want to check error we must use this
}

//DcManager_741FFCFD
//* This will get info of nand in your PSP *
void dcGetNandInfo(int *pagesize, int *ppb, int *totalblocks)
{
	u32 pagesize_, ppb_, totalblocks_;
	
	int k1 = pspSdkSetK1(0);
	pagesize_ = sceNandGetPageSize();
	ppb_ = sceNandGetPagesPerBlock();
    totalblocks_ = sceNandGetTotalBlocks();
	pspSdkSetK1(k1);
	
	(*pagesize) = pagesize_;
	(*ppb) = ppb_;
	(*totalblocks) = totalblocks_;
}

//DcManager_EA3F4DE5
//* This will lock nand *
void dcLockNand(int flag)
{
	int k1 = pspSdkSetK1(0);
	sceNandLock(flag); 
	pspSdkSetK1(k1);
}

//DcManager_4A5FCC2F
//* This will unlock nand *
void dcUnlockNand()
{
	int k1 = pspSdkSetK1(0);
	sceNandUnlock(); 
	pspSdkSetK1(k1);
}

int sub_000002F8() //we can call it GetPpb
{
	int k1 = pspSdkSetK1(0);
	sceNandGetPagesPerBlock();
	pspSdkSetK1(k1);
}

void sub_00001228(u32 page, void *block) //we can call it ReadAccess
{
	int k1 = pspSdkSetK1(0);
	sceNandReadAccess(page, block, NULL, 1, 49);
	pspSdkSetK1(k1);
}

void sub_00004750(u32 page, void *block) //we can call it ReadExtraOnly
{
	int k1 = pspSdkSetK1(0);
    sceNandReadExtraOnly(page, block, 1);
	pspSdkSetK1(k1);
}

//DcManager_7EB5614A
//* This will read block of your nand *
//NOTE: Inspired from raing3s pspReadNandBlock
void dcReadNandBlock(u32 page, u8 *block)
{	
	u32 a0, a1;

	for (a0 = 0; a0 < sub_000002F8(); a0++)
	{
		for (a1 = 0; a1 < 4; a1++)
		{
			sub_00001228(page, block); //read nand access
			sub_00004750(page, block+512); //read extra size only
		}
		page++;
		block += 528;
	}
}

//DcManager_504C82B4
//* This will write nand block *
int dcWriteNandBlock(u32 page, u8 *user, u8 *spare)
{
	int k1 = pspSdkSetK1(0);
    sub_000002F8(); 
	int ret = sceNandWriteAccess(page, user, spare, 1, 49);
	pspSdkSetK1(k1);
	return ret; //In asm is return 0;, but if we want to check error we must use this
}

//DcManager_7E9128B0
//* This will erase nand block *
int dcEraseNandBlock(u32 page)
{
	int k1 = pspSdkSetK1(0);
	int ret = sceNandEraseBlock(page); 
	pspSdkSetK1(k1);
	return ret; //In asm is return 0;, but if we want to check error we must use this
}

//DcManager_109A36FC (New addr: DDA7A73F)
//* UNKNOWN (for now)  *
//NOTE: code is not finished (for now)
void SW(u32 word, u32 address)
{
    int k1 = pspSdkSetK1(0);
	//Some value will be come here
	pspSdkSetK1(k1);
}

//DcManager_4914B8D1 (New addr: 85E170BA)
//* UNKNOWN (for now) *
//NOTE: code is not finished (for now)
u32 LW(u32 address)
{
    int k1 = pspSdkSetK1(0);
	//Some value will be come here
	pspSdkSetK1(k1);
}

int module_start(SceSize args, void *argp)
{
	return 0;
}

int module_stop()
{
	return 0;
}